#pragma once

#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include <fstream>
#include "log.h"
#include "data_segment.h"

namespace safe_udp
{
    constexpr char CLIENT_FILE_PATH[] = "./files/client_files/";
    class UdpClient
    {
    public:
        UdpClient()
        {
            last_in_order_packet_ = -1;
            last_packet_received_ = -1;
            fin_flag_received_ = false;
        }
        ~UdpClient(){}

        // 向服务器发送文件请求
        void SendFileRequest(const std::string &file_name);

        // 创建udp套接字并和服务端连接
        void CreateSocketAndServerConnection(const std::string &server_address, const std::string &port);

        int initial_seq_number_; // 初始序号
        bool is_packet_drop_;    //
        bool is_delay_;
        int prob_value_; // 丢包概率
        // 最后一个排好序的数据包序号（接收窗口末指针，没必要设置起始指针，
        // 排好序后末指针++即可，前面的数据包已经排好序了，不用管）

        int last_in_order_packet_;

        int last_packet_received_; // 最后（也就是最新）接收到的报文序号
        int receiver_window_;      // 接收窗口大小
        bool fin_flag_received_;

    private:
        // 发送确认包，告诉服务器已经成功接收指定序列号的数据包
        void send_ack(int ackNumber);

        // 将数据段插入到data_segments_向量的指定位置，为了保持数据包的顺序。
        void insert(int index, const DataSegment &data_segment);

        // 将新接收的数据段添加到data_segments_向量的末尾。
        int add_to_data_segment_vector(const DataSegment &data_segment);

        int sockfd_;
        int seq_number_;                         // 序号
        int ack_number_;                         // 确认序号
        int16_t length_;                         // 数据包长度
        struct sockaddr_in server_address_;      // 服务器地址
        std::vector<DataSegment> data_segments_; // 存储接收到数据段的vector，用于重组和排序
    };
}